﻿/*
*  	Graffiti 1.1.1
*  	______________________________________________________________________
*  	www.nocircleno.com/graffiti/
*/

/*
* 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* 	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* 	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* 	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* 	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* 	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* 	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* 	OTHER DEALINGS IN THE SOFTWARE.
*/

package com.nocircleno.graffiti.tools {
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.display.LineScaleMode;
	import flash.display.CapsStyle;
	import flash.display.JointStyle;
	import flash.geom.Rectangle;
	import flash.geom.Point;
	import com.nocircleno.graffiti.tools.ITool;
	import com.nocircleno.graffiti.tools.ToolRenderType;
	import com.nocircleno.graffiti.tools.ShapeType;
	
	/**
	* Shape Class allows the user to draw RECTANGLE, SQUARE, OVAL or CIRCLE to the canvas.
	* You can control the stroke and fill of the shape.
	*/
	public class Shape implements ITool {
		
		// store local references for performance reasons
		private const sqrt:Function = Math.sqrt;
		private const pow:Function = Math.pow;
		private const abs:Function = Math.abs;
		private const max:Function = Math.max;
		
		private const RENDER_TYPE:String = ToolRenderType.CLICK_DRAG;
	
		private var _strokeWidth:Number;
		private var _fillColor:int;
		private var _strokeColor:int;
	
		private var _mode:String;
		private var _type:String;
		
		/**
		* The <code>Shape</code> constructor.
		* 
		* @param strokeWidth Stroke width.
		* @param strokeColor Stroke Color, pass -1 for NO stroke on Shape.
		* @param fillColor Fill Color, pass -1 for NO fill in Shape.
		* @param shapeType Type of Shape.
		* @param toolMode Tool mode the Shape will be drawing with.
		* 
		* @example The following code creates a Shape instance.
		* <listing version="3.0" >
		* // create a rectangle shape with red stroke width of 2 and no fill
		* var rectangleShape:Shape = new Shape(2, 0xFF0000, -1, ShapeType.RECTANGLE);
		* </listing>
		*/
		public function Shape(strokeWidth:Number = 1, strokeColor:int = 0x000000, fillColor:int = 0xFFFFFF, shapeType:String = null, toolMode:String = null) {
			
			// store size
			this.strokeWidth = strokeWidth;
			
			// store stroke color
			this.strokeColor = strokeColor;
			
			// store fill color
			this.fillColor = fillColor;
			
			// store type
			type = shapeType;
			
			// store mode
			mode = toolMode;
			
		}
		
		/**
		* Stroke width
		*/
		public function set strokeWidth(strokeW:Number):void {
			
			if(strokeW > 0 || strokeW == -1) {
			
				// set stroke size
				_strokeWidth = strokeW;
				
			}
			
		}
		
		public function get strokeWidth():Number {
			return _strokeWidth;
		}
		
		/**
		* Color of the Stroke, set to -1 for no stroke.
		*/
		public function set strokeColor(color:int):void {
			_strokeColor = color;
		}

		public function get strokeColor():int {
			return _strokeColor;
		}
		
		/**
		* Color of the Fill, set to -1 for no fill.
		*/
		public function set fillColor(color:int):void {
			_fillColor = color;
		}

		public function get fillColor():int {
			return _fillColor;
		}
		
		/**
		* Type of Shape
		*/
		public function set type(shapeType:String):void {
			
			// determine type
			if(shapeType != null && ShapeType.validType(shapeType)) {
				_type = shapeType;
			} else {
				_type = ShapeType.RECTANGLE;
			}
			
		}
		
		public function get type():String {
			return _type;
		}
		
		/**
		* Shape Render Mode
		*/
		public function get renderType():String {
			return RENDER_TYPE;
		}
		
		/**
		* Shape Drawing Mode
		*/
		public function set mode(toolMode:String):void {
			
			// store mode
			if(toolMode != null && ToolMode.validMode(toolMode)) {
				_mode = toolMode;
			} else {
				_mode = ToolMode.NORMAL;
			}
			
		}
		
		public function get mode():String {
			return _mode;
		}
		
		/**
		* The <code>apply</code> method applies the line to the Sprite object passed
		* to the method.
		* 
		* @param drawingTarget Sprite that the Shape will draw to.
		* @param point1 Starting point to apply Shape.
		* @param point2 End point to apply Shape.
		*/
		public function apply(drawingTarget:DisplayObject, point1:Point, point2:Point = null):void {
			
			// cast target as a Sprite
			var targetCast:Sprite = Sprite(drawingTarget);
			
			// calculate dim differences
			var xDiff:Number = point2.x - point1.x;
			var yDiff:Number = point2.y - point1.y;
			
			// if stroke color exists, define line style
			if(_strokeColor != -1) {
				
				// use square corners with miter joints for rectangle and square shapes
				if(_type == ShapeType.RECTANGLE || _type == ShapeType.SQUARE) {
					targetCast.graphics.lineStyle(_strokeWidth, _strokeColor, 1,  false, LineScaleMode.NORMAL, CapsStyle.SQUARE, JointStyle.MITER);
				} else {
					targetCast.graphics.lineStyle(_strokeWidth, _strokeColor, 1);
				}
				
			}
			
			// if fill color exists, start fill
			if(_fillColor != -1) {
				targetCast.graphics.beginFill(_fillColor, 1);
			}
			
			// draw shape
			if(_type == ShapeType.RECTANGLE) {
				targetCast.graphics.drawRect(point1.x, point1.y, xDiff, yDiff);
			} if(_type == ShapeType.SQUARE) {
				var segmentLength:Number = abs(max(xDiff, yDiff));
				targetCast.graphics.drawRect(point1.x, point1.y, point2.x < point1.x ? -segmentLength : segmentLength,  point2.y < point1.y ? -segmentLength : segmentLength);
			} else if(_type == ShapeType.OVAL) {
				targetCast.graphics.drawEllipse(point1.x, point1.y, xDiff, yDiff);
			} else if(_type == ShapeType.CIRCLE) {
				var lineLength:Number = sqrt(pow(point2.x - point1.x, 2) + pow(point2.y - point1.y, 2));
				targetCast.graphics.drawCircle(point1.x + ((xDiff)/2), point1.y + ((yDiff)/2), lineLength/2);
			}
			
			// if fill color exists then end fill
			if(_fillColor != -1) {
				targetCast.graphics.endFill();
			}
			
		}
		
	}
		
}